<script lang="ts" setup>
import * as Vue from 'vue'
import plugin from './plugin'

enum LoadStatus {
  /**
   * 加载中
   */
  LOADING,
  /**
   * 加载成功
   */
  SUCCESS,
  /**
   * 加载失败
   */
  ERROR,
}

const loadStatus = ref(LoadStatus.LOADING)
/**
 * 远程组件
 */
const CurrentComponent = Vue.shallowRef()

const props = defineProps({
  /**
   * @deprecated
   */
  devUrl: {
    type: String,
    required: false,
    default: null,
  },
  /**
   * 组件渲染上下文
   */
  context: {
    type: Object,
    default: () => ({}),
  },
  /**
   * 服务接口名称
   */
  service: {
    type: String,
    required: true,
  },
  /**
   * 挂载到全局的组件名称
   */
  name: {
    type: String,
    default: 'value',
  },
  /**
   * 挂载到全局的上下文名称
   */
  contextName: {
    type: String,
    default: '',
  },
  /**
   * 传递到远程组件的属性
   */
  properties: {
    type: Object,
    default: () => ({}),
  },
  /**
   *  未加载到数据立即隐藏
   */
  hideOnMiss: {
    type: Boolean,
    default: false,
  },
})

Vue.onMounted(() =>
  loadRemoteComponent()
    .then((value) => {
      CurrentComponent.value = value
      loadStatus.value = value ? LoadStatus.SUCCESS : LoadStatus.ERROR
    })
    .catch(() => {
      loadStatus.value = LoadStatus.ERROR
    }),
)
// 是否开发环境
const isDev = import.meta.env.VITE_NODE_ENV === 'development'

/**
 * 通过远程url 加载远程组件
 */
function loadRemoteComponent() {
  //准备上下文
  return renderScript(
    // `${(isDev && props.devUrl) || import.meta.env.VITE_BASE_URL + props.service}/public/pc/${props.name}/index.umd.js`,
    // props.name,
    `${isDev ? import.meta.env.VITE_PLUGIN_URL : import.meta.env.VITE_BASE_URL}${props.service}/public/pc/${props.name}/index.umd.js`,
    props.name,
    props.contextName || `${props.name}Context`,
    props.context,
  )
}

function renderScript(url: string, resultName: string, contextName?: string, context = {}) {
  contextName = contextName || `${resultName}Context`
  //@ts-ignore
  let script = null
  //渲染组件
  return new Promise((resolve, reject) => {
    let value
    if ((value = plugin.tryGet(url))) {
      resolve(value)
      return true
    }
    //@ts-ignore
    window[contextName] = { Vue, ...context }
    script = document.createElement('script')
    script.onload = () => {
      if ((value = plugin.get(url))) {
        resolve(value)
        return
      }
      //@ts-ignore
      value = window[resultName]
      resolve(plugin.set(url, value))
    }
    script.onerror = (event, source, lineno, colno, error) => {
      if ((value = plugin.get(url))) {
        resolve(value)
        return
      }
      reject({ event, error })
    }
    script.src = url
    document.body.appendChild(script)
  }).finally(() => {
    //@ts-ignore
    script && document.body.removeChild(script)
    plugin.remove(url).then((result) => {
      if (result) {
        return
      }
      //删除上下文
      //@ts-ignore
      delete window[contextName]
      //删除组件
      //@ts-ignore
      delete window[resultName]
    })
  })
}
</script>

<template>
  <el-skeleton v-show="loadStatus === LoadStatus.LOADING" :rows="6" />
  <current-component v-if="loadStatus === LoadStatus.SUCCESS" :properties="props.properties" />
  <el-empty v-show="!hideOnMiss && loadStatus === LoadStatus.ERROR" description="未获取到远程组件" />
</template>
